﻿
#import "C:\Users\linwei\AppData\Roaming\MetaQuotes\Terminal\EB3C3B239AFB8B62B7EC3451D269EB1E\MQL5\Projects\SocketPipeClientDLL.dll"
	int InitSocket();
 	int CloseSocket();
	int GetPacket(int &handle);
	int SendPacket(int handle);
    
    // For PacketReader
	int PacketReaderFree(int handle);
	int RequestGetLong(int handle, long &output);
	int RequestGetInt(int handle, int &output);
	int RequestGetDouble(int handle, double &output);
	int RequestGetString(int handle, char &pChar[], int length);
    
    // For PacketWriter
	int PacketWriterCreate();
	void PacketWriterFree(int handle);
	int PacketWriterSetInt(int handle, int data);
	int PacketWriterSetLong(int handle, long data);
	int PacketWriterSetDouble(int handle, double data);
	int PacketWriterSetString(int handle, char &pChar[]);

#import

enum RequestType
{
	RequestType_None = 0,
	RequestType_Test,
	RequestType_SendOrder,
	RequestType_SendOrder_Result,
	RequestType_RateByTime,
	RequestType_RateByTime_Result,
	RequestType_SymbolNameList,
	RequestType_SymbolNameList_Result,
	RequestType_RateByCount,
	RequestType_RateByCount_Result,
	RequestType_RateByTime2,
	RequestType_RateByTime2_Result,
    RequestType_MAX,
};   

string gRequestNameArr[RequestType_MAX] = 
{
    "None",
    "RequestType_Test",
    "RequestType_SendOrder",
    "RequestType_SendOrder_Result",
    "RequestType_RateByTime",
    "RequestType_RateByTime_Result",
    "RequestType_SymbolNameList",
    "RequestType_SymbolNameList_Result"
	"RequestType_RateByCount",
	"RequestType_RateByCount_Result",
	"RequestType_RateByTime2",
	"RequestType_RateByTime2_Result",
};


//+------------------------------------------------------------------
//| Common                                       
//+------------------------------------------------------------------
#define D_SYMBOL_NAME_MAX (24)
#define D_TIME_STRING_MAX (20)
#define D_STRING_LENGTH_MAX (1024 * 100)

#define D_DEFAULT_BUFFER_SIZE (1024)
#define RATE_INFO_MAX_LENGTH (1024 *10)
#define D_RATE_INFO_PACKET_SIZE (100)

int RequestGetString(int handle, string &str)
{
    char strArr[D_STRING_LENGTH_MAX];
    int ret = RequestGetString(handle, strArr, D_STRING_LENGTH_MAX);
    str = CharArrayToString(strArr, 0, D_STRING_LENGTH_MAX);
    return ret;
}

int PacketWriterSetString(int writeHandle, string str)
{
    char strArr[D_STRING_LENGTH_MAX];
    StringToCharArray(str, strArr, 0, D_STRING_LENGTH_MAX);
    // Set SymbolName
    return PacketWriterSetString(writeHandle, strArr); 
}


int RequestGetDatetime(int handle, datetime &time)
{
    string str;
    int ret = RequestGetString(handle, str);
    time =  StringToTime(str);
    return ret;
}

int PacketWriterSetDatetime(int writeHandle, datetime time)
{
    // Set Time
    char timeArr[D_TIME_STRING_MAX];
    StringToCharArray(TimeToString(time), timeArr, 0);
    return PacketWriterSetString(writeHandle, timeArr);
}




//+------------------------------------------------------------------
//| RequestType_SendOrder                                       
//+------------------------------------------------------------------
extern double LotSize = 0.01;

enum SendOrderCmd
{
   CMD_NONE = 0,
   CMD_BUY = 1,
   CMD_SELL = 2,
   CMD_CLOSE = 3,
};
struct SendOrderReq
{
	string symbolName;
	SendOrderCmd cmd;
    int magicNumber;
};

void GetSendOrderReq(int readHandle, SendOrderReq &req)
{
    RequestGetString(readHandle, req.symbolName);
    
    int cmdValue;
    RequestGetInt(readHandle, cmdValue);
    req.cmd =  (SendOrderCmd)cmdValue;
    
    RequestGetInt(readHandle, req.magicNumber);
}

void SendOrderResult(int result)
{
    int writeHandle = PacketWriterCreate();
    // Set type
    PacketWriterSetInt(writeHandle, RequestType_SendOrder_Result);
    PacketWriterSetInt(writeHandle, result);
    SendPacket(writeHandle);
    PacketWriterFree(writeHandle);
}

string GetTradeComment(SendOrderReq &req, string action)
{
	string res = "";
	res += IntegerToString(req.magicNumber) + ": " ;
	res += TimeToString(TimeCurrent(),TIME_DATE|TIME_MINUTES) ;
	res += " " + action;
	return res;
}

ulong GetPositionByMagicNum(ulong MagicNum)
{
	ulong  position_ticket=0;
	int total=PositionsTotal(); 
	int loopCnt;
	for( loopCnt=0; loopCnt<total; loopCnt++)
	{
		position_ticket=PositionGetTicket(loopCnt);// ticket of the position
		ulong  magic=PositionGetInteger(POSITION_MAGIC);// MagicNumber of the position
		
		if(magic == MagicNum)
			break;
	}

	if( loopCnt<total )
		return position_ticket;
	else
		return 0;

}

bool PositionClose(ulong ticket_num)
{
	MqlTradeRequest request = {0};
	MqlTradeResult  result = {0};
	bool ret;
	#ifdef bbb
	if( OrderSelect(ticket_num) == false )
	{
		PrintFormat("OrderSelect error %d",GetLastError());  // if unable to send the request, output the error code
		//--- information about the operation   
		PrintFormat("ticket_num=%I64u",ticket_num);
		return false;
	}
	#endif
	string	position_symbol = PositionGetString(POSITION_SYMBOL);// symbol 
	int		digits = (int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);// number of decimal places
	ulong 	magic = PositionGetInteger(POSITION_MAGIC);// MagicNumber of the position
	double	volume = PositionGetDouble(POSITION_VOLUME); // volume of the position
	ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);    // type of the position
	
	request.action   = TRADE_ACTION_DEAL;                     // 交易操作类型
	request.position = ticket_num;
	request.symbol   = position_symbol;                              // 交易品种
	request.volume   = volume;                                   // 0.1手交易量 
	request.deviation= 5;                                     // 允许价格偏差
	request.magic    = magic;                             // 订单幻数
	
	if(type == POSITION_TYPE_BUY)
	{
		request.price = SymbolInfoDouble(position_symbol,SYMBOL_BID);
		request.type = ORDER_TYPE_SELL;
	}
	else
	{
		request.price = SymbolInfoDouble(position_symbol,SYMBOL_ASK);
		request.type = ORDER_TYPE_BUY;
	}
	//--- output information about the closure
	PrintFormat("Close #%I64d %s %s",request.magic,position_symbol,EnumToString(type));
	//--- send the request
	if(!OrderSend(request,result))
	{
	   ret = false;
		PrintFormat("OrderSend error %d",GetLastError());  // if unable to send the request, output the error code
	}
	else
	   ret = true;
	//--- information about the operation   
	PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
	//---
	
	return ret;
}

void SendOrderRequest(int handle)
{
	MqlTradeRequest request = {0};
	MqlTradeResult  result = {0};
	ulong	ticket_num;
   SendOrderReq req;
   GetSendOrderReq(handle, req);
   
	ticket_num = GetPositionByMagicNum(req.magicNumber);
	
    if( ticket_num > 0 )
    {
#ifdef aaa
		if( OrderSelect(ticket_num) == false )
		{
			PrintFormat("OrderSelect error %d",GetLastError());  // if unable to send the request, output the error code
			//--- information about the operation   
			PrintFormat("ticket_num=%I64u",ticket_num);
			SendOrderResult(1);
			return;
		}
#endif
		ENUM_POSITION_TYPE type = 
			(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);    // type of the position
			
        if( (type == POSITION_TYPE_BUY && req.cmd == CMD_BUY) ||
            (type == POSITION_TYPE_SELL && req.cmd == CMD_SELL) )
		{
            SendOrderResult(0);
            return ;
        }
			
        if(PositionClose(ticket_num) == false)
        {
            SendOrderResult(1);
            return;        
        }
    }
	
	ZeroMemory(request);
	ZeroMemory(result);   
    if( req.cmd == CMD_BUY )
    {
		request.action   = TRADE_ACTION_DEAL;                     // 交易操作类型
		request.symbol   = req.symbolName;                              // 交易品种
		request.volume   = LotSize;                                   // 0.1手交易量 
		request.type     = ORDER_TYPE_BUY;                        // 订单类型
		request.price    = SymbolInfoDouble(req.symbolName,SYMBOL_ASK); // 持仓价格
		request.deviation= 5;                                     // 允许价格偏差
		request.magic    = req.magicNumber;                          // 订单幻数
		request.comment  = GetTradeComment(req, "Buy");
	
	   PrintFormat("Buy #%I64d %s %d",request.magic,request.symbol,request.price);
		if(!OrderSend(request,result))
		{
			PrintFormat("OrderSend error %d",GetLastError());     // 如果不能发送请求，输出错误代码	
 		    SendOrderResult(1);
 		}
 		PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);	}
    else if( req.cmd == CMD_SELL )
    {
		request.action   = TRADE_ACTION_DEAL;                     // 交易操作类型
		request.symbol   = req.symbolName;                              // 交易品种
		request.volume   = LotSize;                                   // 0.1手交易量 
		request.type     = ORDER_TYPE_SELL;                        // 订单类型
		request.price    = SymbolInfoDouble(req.symbolName,SYMBOL_BID); // 持仓价格
		request.deviation= 5;                                     // 允许价格偏差
		request.magic    = req.magicNumber;                          // 订单幻数
		request.comment  = GetTradeComment(req, "Sell");
		
	   PrintFormat("Sell #%I64d %s %d",request.magic,request.symbol,request.price);
		if(!OrderSend(request,result))
		{
			PrintFormat("OrderSend error %d",GetLastError());     // 如果不能发送请求，输出错误代码	
		   SendOrderResult(1);
		}
		PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
	}
	else
	{
		PrintFormat("OrderSend cmd error %d",req.cmd);
	}
	
    
    SendOrderResult(0);
	return;
}

//+------------------------------------------------------------------
//| RequestType_RateByTime2                                    
//+------------------------------------------------------------------
struct RatesByTime2Request
{
	string symbolName;
	ENUM_TIMEFRAMES timeFrame;
	datetime startTime;
};
void GetRatesByTime2Req(int readHandle, RatesByTime2Request &req)
{
    RequestGetString(readHandle, req.symbolName);
    int intValue;
    RequestGetInt(readHandle, intValue);
    req.timeFrame = (ENUM_TIMEFRAMES)intValue;
    RequestGetDatetime(readHandle, req.startTime);
}

void SetRateInfo(int handle, MqlRates &info)
{
    PacketWriterSetDatetime(handle, info.time);
    PacketWriterSetDouble(handle, info.open);
    PacketWriterSetDouble(handle, info.close);
    PacketWriterSetDouble(handle, info.high);
    PacketWriterSetDouble(handle, info.low);
    PacketWriterSetLong(handle, info.tick_volume);
    PacketWriterSetLong(handle, info.real_volume);
    PacketWriterSetInt(handle, info.spread);
}

int CheckLoadHistory(string symbol,ENUM_TIMEFRAMES period,datetime start_date) 
  { 
   datetime first_date=0; 
   datetime times[100]; 
//--- check symbol & period 
   if(symbol==NULL || symbol=="") symbol=Symbol(); 
   if(period==PERIOD_CURRENT)     period=Period(); 
//--- check if symbol is selected in the Market Watch 
   if(!SymbolInfoInteger(symbol,SYMBOL_SELECT)) 
     { 
      if(GetLastError()==ERR_MARKET_UNKNOWN_SYMBOL) return(-1); 
      SymbolSelect(symbol,true); 
     } 
//--- check if data is present 
   SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE,first_date); 
   if(first_date>0 && first_date<=start_date) return(1); 
//--- don't ask for load of its own data if it is an indicator 
   if(MQL5InfoInteger(MQL5_PROGRAM_TYPE)==PROGRAM_INDICATOR && Period()==period && Symbol()==symbol) 
      return(-4); 
//--- second attempt 
   if(SeriesInfoInteger(symbol,PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_date)) 
     { 
      //--- there is loaded data to build timeseries 
      if(first_date>0) 
        { 
         //--- force timeseries build 
         CopyTime(symbol,period,first_date+PeriodSeconds(period),1,times); 
         //--- check date 
         if(SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE,first_date)) 
            if(first_date>0 && first_date<=start_date) return(2); 
        } 
     } 
//--- max bars in chart from terminal options 
   int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); 
//--- load symbol history info 
   datetime first_server_date=0; 
   while(!SeriesInfoInteger(symbol,PERIOD_M1,SERIES_SERVER_FIRSTDATE,first_server_date) && !IsStopped()) 
      Sleep(5); 
//--- fix start date for loading 
   if(first_server_date>start_date) start_date=first_server_date; 
   if(first_date>0 && first_date<first_server_date) 
      Print("Warning: first server date ",first_server_date," for ",symbol, 
            " does not match to first series date ",first_date); 
//--- load data step by step 
   Print("load data from ", first_date, " to ", start_date);
   int fail_cnt=0; 
   while(!IsStopped()) 
     { 
      //--- wait for timeseries build 
      while(!SeriesInfoInteger(symbol,period,SERIES_SYNCHRONIZED) && !IsStopped()) 
         Sleep(5); 
      //--- ask for built bars 
      int bars=Bars(symbol,period); 
      if(bars>0) 
        { 
         if(bars>=max_bars) return(-2); 
         //--- ask for first date 
         if(SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE,first_date)) 
            if(first_date>0 && first_date<=start_date) return(0); 
        } 
      //--- copying of next part forces data loading 
      int copied=CopyTime(symbol,period,bars,100,times); 
      if(copied>0) 
        { 
         Print("load data at  ", times[0], " / ", start_date);
         //--- check for data 
         if(times[0]<=start_date)  return(0); 
         if(bars+copied>=max_bars) return(-2); 
         fail_cnt=0; 
        } 
      else 
        { 
         //--- no more than 100 failed attempts 
         fail_cnt++; 
         if(fail_cnt>=100) return(-5); 
         Sleep(10); 
        } 
     } 
//--- stopped 
   return(-3); 
  } 
  
void RateByTimeRequest2(int handle)
{
    RatesByTime2Request req;
    GetRatesByTime2Req(handle, req);
    Print("RateByTimeRequest2: ", req.symbolName, ", ", req.timeFrame, ", ", req.timeFrame);
    int writeHandle;
    
    MqlRates rates[];
	
    ArraySetAsSeries(rates,false);
	
	datetime current_time=TimeCurrent();  
	int res = CheckLoadHistory(req.symbolName, req.timeFrame, req.startTime);
	switch(res) 
     { 
      case -1 : Print("Unknown symbol ",req.symbolName);             break; 
      case -2 : Print("Requested bars more than max bars in chart"); break; 
      case -3 : Print("Program was stopped");                        break; 
      case -4 : Print("Indicator shouldn't load its own data");      break; 
      case -5 : Print("Load failed");                                break; 
      case  0 : Print("Loaded OK");                                  break; 
      case  1 : Print("Loaded previously");                          break; 
      case  2 : Print("Loaded previously and built");                break; 
      default : Print("Unknown result"); 
     } 
	 
    int remainCnt = CopyRates(
		req.symbolName, 
		req.timeFrame, 
		current_time, 
		req.startTime, 
		rates );
            
	
	if( remainCnt == 0 )
	{
      writeHandle = PacketWriterCreate();
		PacketWriterSetInt(writeHandle, 0);	
		SendPacket(writeHandle);
		PacketWriterFree(writeHandle);
		return;
	}
	else if( remainCnt < 0 )
	{
		Print("RateByTimeRequest2 CopyRates error: ",remainCnt);
      writeHandle = PacketWriterCreate();
		PacketWriterSetInt(writeHandle, 0);	
		SendPacket(writeHandle);
		PacketWriterFree(writeHandle);
		return;
	}
	
	Print("RateByTimeRequest2 sendCnt: ",remainCnt);

	int sendCnt;
	int pos=0;
	
	if( remainCnt > RATE_INFO_MAX_LENGTH )
	{
		sendCnt = RATE_INFO_MAX_LENGTH;
	}
	else
	{
		sendCnt = remainCnt;
	}
		
	// Set type
   writeHandle = PacketWriterCreate();
	PacketWriterSetInt(writeHandle, RequestType_RateByCount_Result);
	PacketWriterSetInt(writeHandle, sendCnt);
	for(int i=0; i<sendCnt; i++)
	{
		SetRateInfo(writeHandle, rates[pos+i]);
	}
#define D_DEBUG		
#ifdef D_DEBUG	
	if(sendCnt>0)
	{
	   Print("RateByTimeRequest2 send[", pos, "]: ",sendCnt, " ", 
	   rates[pos].time, "-", rates[pos+sendCnt-1].time);
   }
   else
   {
	   Print("RateByTimeRequest2 send[", pos, "]: ",sendCnt);
   }
#endif	   
	SendPacket(writeHandle);
	PacketWriterFree(writeHandle);
  
    
}


//+------------------------------------------------------------------
//| RequestType_SymbolNameList                                       
//+------------------------------------------------------------------
void SymbolNameListRequest(int handle)
{
   // TODO
}

//+------------------------------------------------------------------
//| RequestType_Test                                       
//+------------------------------------------------------------------
void TestQequest(int readHandle)
{
	int writeHandle = PacketWriterCreate();
	double valueDouble;
	int valueInt;
	string valueStr;
	
	// Set type
	PacketWriterSetInt(writeHandle, RequestType_Test); 
   
	RequestGetDouble(readHandle, valueDouble);
	PacketWriterSetDouble(writeHandle, valueDouble);

	RequestGetInt(readHandle, valueInt);
	PacketWriterSetInt(writeHandle, valueInt);

	RequestGetString(readHandle, valueStr);
	PacketWriterSetString(writeHandle, valueStr);

	RequestGetString(readHandle, valueStr);
	PacketWriterSetString(writeHandle, valueStr);
   
	SendPacket(writeHandle);
	PacketWriterFree(writeHandle);
}



void OnTick()
{


}

void OnStart()
{
    //---
    ulong debugCnt = 0;
    int i=0;
    int readHandle, type, ret;

    InitSocket();
    while(1)
    {

        ret = GetPacket(readHandle);
        if( ret < 0 ) // net connected
        {
            printf("[%I64u] Waiting connection...", debugCnt++);
            Sleep(500);
            continue;
        }
        else if(ret == 0) // receiving data
        {
            printf("[%I64u] Receiving data...", debugCnt++);
            continue;
        }
        
        if(readHandle == 0)
	      {
			   printf("[%I64u] Packet get error...", debugCnt++);
            continue;
        }
        RequestGetInt(readHandle, type);
        Print("Get ", gRequestNameArr[type], "!");
        
        if(type == RequestType_SymbolNameList)
        {
            SymbolNameListRequest(readHandle);
        }
        else if(type == RequestType_SendOrder)
        {
            SendOrderRequest(readHandle);
        }
        else if(type == RequestType_RateByTime2)
        {
            RateByTimeRequest2(readHandle);
        }
        else if(type == RequestType_Test)
        {
            TestQequest(readHandle);
        }        
        else if(type != 0)
        {
            Print("*** Get Request!", type);
   
        }
        PacketReaderFree(readHandle);
    }          
}
